#include "TreeView.h"
#include <QtGui>

#include <QGLWidget>


namespace Xps
{

	TreeView::TreeView(XpsAssets::AssetManager* am, QWidget * parent) : QGraphicsView(parent)
	{
		this->am = am;
		props = new Properties(am,this);
		zoom_steps = 0;

		setScene(new QGraphicsScene());
		setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
		setDragMode(QGraphicsView::RubberBandDrag);
		setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
		setBackgroundBrush(QBrush(QColor(243,250,255)));		
		centerOn(1000,1000);
		
		setupActions();

		connect(scene(), SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
		connect(am, SIGNAL(sNewTreeNode(int)), this, SLOT(addNode(int)));
		connect(am, SIGNAL(sNewLink(int,int,int)), this, SLOT(addLink(int,int,int)));
		connect(am, SIGNAL(sAttributeRemoved(int)), this, SLOT(remAttribute(int)));
		scene()->update();
	}

	TreeView::~TreeView(void)
	{
	}

	void TreeView::contextMenuEvent(QContextMenuEvent * event)
	{
		QMenu* menu = new QMenu();
		
		menu->addAction(aCreateLink);
		menu->addAction(aBreakLink);
		menu->addSeparator();
		menu->addAction(aCreateConstraint);
		menu->addSeparator();
		menu->addAction(aDelete);
		menu->exec(event->globalPos());
	}

	void TreeView::selectionChanged()
	{
		static Item* lsi = NULL;

		if (lsi != NULL)
		{
			if (lsi->getType() == XpsAssets::TreeNode::CONSTRAINT)
				((ConstraintItem*)lsi)->removeChildMarker();
			
			lsi = NULL;
		}

		if (scene()->selectedItems().count() == 1)
		{
			Item* item = (Item*) scene()->selectedItems().at(0);
			
			if (item->getType() == XpsAssets::TreeNode::CONSTRAINT)
			{
				((ConstraintItem*)item)->updateChildMarker();
				props->setItem(1,item);
				props->show();
			}
			else if (item->getType() == XpsAssets::TreeNode::QUESTION)
			{
				props->setItem(1,item);
				props->show();
			}
			lsi = item;
		}
		else
		{
			props->setItem(scene()->selectedItems().count());
		}

	}

	void TreeView::cleanUp()
	{
		QList<LinkItem*> linklist = links;

		for (int i = 0; i < linklist.count(); i++)
		{
			LinkItem* li = linklist.at(i);

			scene()->removeItem(li);
			links.removeOne(li);
			delete li;
		}

		QList<QGraphicsItem*> items =  scene()->items();

		while (!items.isEmpty())
		{
			QGraphicsItem* item = items.takeAt(0);

			scene()->removeItem(item);
			delete item;
		}
	}

	void TreeView::addLink(int id1, int id2, int mode)
	{
		Item* i1 = items.value(id1);
		Item* i2 = items.value(id2);

		addLinkItem(i1, i2, mode);
	}

	void TreeView::addNode(int id)
	{
		ConstraintItem* citem = NULL;
		Item* item = NULL;
		XpsAssets::TreeNode* node = am->getNode(id);
		XpsAssets::ConstraintNode* cnode;

		switch (node->_type)
		{
		case XpsAssets::TreeNode::QUESTION:
			item = addQuestionItem(node->_refId);
			break;

		case XpsAssets::TreeNode::START:
			item = addStartItem();
			break;

		case XpsAssets::TreeNode::END:
			item = addEndItem();
			break;

		case XpsAssets::TreeNode::CONSTRAINT:
			cnode = (XpsAssets::ConstraintNode*) node;		
			citem = addConstraintItem();
			(*citem->attributes()) = cnode->attributes;
			item = citem;
			break;
		};
		items.insert(id, item);
		item->setPos(node->_position);
	}

	void TreeView::remSelectedItems()
	{
		QList<QGraphicsItem*> selection = scene()->selectedItems();
		
		for (int i = 0; i < selection.count(); i++)
		{
			isolateItem((Xps::Item*) selection.at(i));
			scene()->removeItem(selection.at(i));
		}
	}

	void TreeView::remAttribute(int id)
	{
		QList<QGraphicsItem*> items = scene()->items();

		QList<QGraphicsItem*> selection = scene()->selectedItems();
		
		if (selection.count() == 1)
		{
			Item* item = (Item*) selection.at(0);

			if (item->getType() == XpsAssets::TreeNode::CONSTRAINT)
			{
				props->cd->remAttribute(id);
			}
		}

		for (int i = 0; i < items.count(); i++)
		{
			Item* item = (Item*) items.at(i);

			if (item->getType() != XpsAssets::TreeNode::CONSTRAINT)
				continue;

			ConstraintItem* ci = (ConstraintItem*) item;

			ci->attributes()->remove(id);
		}
	}

	Tree::QuestionItem* TreeView::addQuestionItem(int qid)
	{
		Tree::QuestionItem* item;
		
		item = new Tree::QuestionItem(qid,am);
		item->setPos(getCreationPosition());
		scene()->addItem(item);

		qDebug() << "TreeView: Created Question";
		return item;
	}

	QPointF TreeView::getCreationPosition()
	{
		qDebug() << "Create at: " << QCursor::pos();

		if (hasFocus())
		{
			// use mouse position
			QPointF p = mapToScene(mapFromGlobal(QCursor::pos()));
			qDebug() << "pos: " << p;
			return p;
		}
		
		// center
		return QPointF(0,0);
	}

	Item* TreeView::addStartItem()
	{
		Item* item;
				
		QList<QGraphicsItem*> items = scene()->items();

		// check if a start item already exists
		for (int i = 0; i < items.count(); i++)
		{
			Item* item = (Item*) items.at(i);

			if (item->getType() == XpsAssets::TreeNode::START)
			{
				QMessageBox::critical(this, "Error", "Only one StartItem per Scene allowed.");
				return NULL;
			}
		} // end of check

		item = new StartItem();
		item->setPos(480,500);
		scene()->addItem(item);
		
		qDebug() << "TreeView: Created Start";
		return item;
	}

	Item* TreeView::addEndItem()
	{
		Item* item;

		item = new EndItem();
		item->setPos(480,500);
		scene()->addItem(item);
		
		qDebug() << "TreeView: Created End";
		return item;
	}

	ConstraintItem* TreeView::addConstraintItem()
	{
		ConstraintItem* item;

		item = new ConstraintItem();
		item->setPos(getCreationPosition());
		scene()->addItem(item);
		
		qDebug() << "TreeView: Created Constraint";
		return item;
	}

	void TreeView::breakLink()
	{
		QList<QGraphicsItem*> selection = scene()->selectedItems();

		if (selection.count() == 2)
		{
			Item* i1 = (Item*)selection.at(0);
			Item* i2 = (Item*)selection.at(1);
			
			breakLink(i1 ,i2);
		}
	}

	void TreeView::isolateItem(Item* item)
	{
		QList<LinkItem*> linklist = links;

		for (int i = 0; i < linklist.count(); i++)
		{
			LinkItem* li = linklist.at(i);

			if (li->parent() == item || li->child() == item)
			{
				scene()->removeItem(li);
				links.removeOne(li);
				delete li;
			}
		}
	}

	void TreeView::breakLink(Item* i1, Item* i2)
	{
		LinkItem* li = NULL;

		// search for link
		for (int i = 0; i < links.count(); i++)
		{
			if ((links.at(i)->parent() == i1 && links.at(i)->child() == i2) ||
				(links.at(i)->parent() == i2 && links.at(i)->child() == i1))
			{
				li = links.takeAt(i);
				break;
			}
		}

		// cancel did not find link between items
		if (li == NULL) return;

		// if parent is constraint remove from true/falsenode
		if (li->parent()->getType() == XpsAssets::TreeNode::CONSTRAINT)
		{
			if (!((ConstraintItem*) li->parent())->removeChildNode(li->child()))
				qDebug() << "Treeview (error): could not remove child node from constraint";
		}

		scene()->removeItem(li);
		delete li;
		li = NULL;
	}

	void TreeView::addLinkItem()
	{
		QList<QGraphicsItem*> selection = scene()->selectedItems();

		if (selection.count() == 2)
		{
			Item* i1 = (Item*)selection.at(0);
			Item* i2 = (Item*)selection.at(1);

			addLinkItem(i1, i2);
		}
	}

	void TreeView::addLinkItem(Item* i1, Item* i2, int mode)
	{
		addLinkItem(i1,i2,true);
		
		if (mode == 0 || i1->getType() != XpsAssets::TreeNode::CONSTRAINT)
			return;
		
		ConstraintItem* ci = (ConstraintItem*) i1;
		
		if (mode == 1 && i2 != ci->trueNode())
			ci->hiddenSwap();

		if (mode == 2 && i2 != ci->falseNode())
			ci->hiddenSwap();

	}

	void TreeView::addLinkItem(Item* i1, Item* i2, bool ignore)
	{
		if (linkExists(i1,i2))
			return;
				
		if (i1->scenePos().y() > i2->scenePos().y() && ignore == false) 
		{
			Item* tmp = i1;
			i1 = i2;
			i2 = tmp;
		}

		if (i1->getType() == XpsAssets::TreeNode::END) 
			return; // end items can not be a parent

		if (i1->getType() == XpsAssets::TreeNode::CONSTRAINT)
		{
			ConstraintItem* ci = (ConstraintItem*) i1;
			
			if (!ci->addChildNode(i2))
				return; // Constraint has used all its links
		}
		else if (isParent(i1))
			return; // only constraints can have to children

		LinkItem* link = new LinkItem(i1,i2);
		scene()->addItem(link);	
		links.append(link);
		qDebug() << "TreeView: Created Link";
	}

	bool TreeView::linkExists(Item* i1, Item* i2)
	{
		for (int i = 0; i < links.count(); i++)
		{
			if ((links.at(i)->parent() == i1 && links.at(i)->child() == i2) ||
				(links.at(i)->parent() == i2 && links.at(i)->child() == i1))
				return true;
		}
		return false;
	}

	bool TreeView::isParent(Item* item)
	{
		for (int i = 0; i < links.count(); i++)
		{
			if (links.at(i)->parent() == item)
				return true;
		}
		return false;
	}

	void TreeView::zoomIn()
	{
		if (zoom_steps > 10) return;

		zoom_steps++;
		scale(1.1, 1.1);
	}

	void TreeView::zoomOut()
	{
		if (zoom_steps < -10) return;

		zoom_steps--;
		scale(0.9, 0.9);
	}

	void TreeView::setupActions()
	{
				
		QAction* action;
		
		action = new QAction(QIcon(":/rs/images/questionitem.png"),"Create Question Item", this);
		aCreateQuestionItem = action;
		actions.append(action);	
		
		action = new QAction(QIcon(":/rs/images/start.png"),"Create Start Item", this);
		connect(action, SIGNAL(triggered()), this, SLOT(addStartItem()));
		actions.append(action);	
		
		action = new QAction(QIcon(":/rs/images/end.png"),"Create End Item", this);
		connect(action, SIGNAL(triggered()), this, SLOT(addEndItem()));
		actions.append(action);	

		aCreateConstraint = new QAction(QIcon(":/rs/images/constraint.png"),"Create Constraint Item", this);
		connect(aCreateConstraint, SIGNAL(triggered()), this, SLOT(addConstraintItem()));
		actions.append(aCreateConstraint);

		aCreateLink = new QAction(QIcon(":/rs/images/createlink.png"),"Create Link", this);
		connect(aCreateLink, SIGNAL(triggered()), this, SLOT(addLinkItem()));
		actions.append(aCreateLink);	
		
		aBreakLink = new QAction(QIcon(":/rs/images/breaklink.png"),"Break Link", this);
		connect(aBreakLink, SIGNAL(triggered()), this, SLOT(breakLink()));
		actions.append(aBreakLink);	

		aDelete = new QAction(QIcon(":/rs/images/delete.png"),"Delete", this);
		connect(aDelete, SIGNAL(triggered()), this, SLOT(remSelectedItems()));
		actions.append(aDelete);	

		action = new QAction(QIcon(":/rs/images/zoomin.png"),"Zoom In", this);
		connect(action, SIGNAL(triggered()), this, SLOT(zoomIn()));
		actions.append(action);			
		
		action = new QAction(QIcon(":/rs/images/zoomout.png"),"Zoom Out", this);
		connect(action, SIGNAL(triggered()), this, SLOT(zoomOut()));
		actions.append(action);	
	}
}